#include "rtc.h"

/** converts BCD (Binary Coded Decimal) to decimal
 */
Byte bcd2dec(Byte i)
{
	return ( (i >> 4) * 10 ) + ( i & 0x0F );
}


/** converts decimal to BCD (Binary Coded Decimal)
 */
Byte dec2bcd(Byte i)
{
  return  ( ( i/10 ) << 4) | ( i%10 ) ;
}

/** Wait until data in rtc is valid.
 * Data is valid until +/- 240 usec after this function returns,
 * thus a read/write can be done to the RTC within this time period
 */
void rtc_valid()
{
  outportb( RTC_ADDR_REG, RTC_STAT_A);
  uchar stat_A  = inportb(RTC_DATA_REG) & 0x80;

  while (stat_A == RTC_UIP)
  {
      stat_A = inportb(RTC_DATA_REG) & 0x80;
  }
}

/** Returns rtc data from I/O address add. Doesn't check valid bit
 */
Byte read_rtc(Byte add)
{
	disable_int();
	outportb(RTC_ADDR_REG, add);
	Byte value = inportb(RTC_DATA_REG);
	enable_int();
	return value;
}

/** Returns rtc data from I/O address add. Check valid bit
 */
Byte read_rtcv(Byte add)
{
	rtc_valid();
	return read_rtc(add);
}

/** Write value to I/O address add. Doesn't check valid bit
 */
void write_rtc(Byte add, Byte value)
{
	disable_int();
	outportb(RTC_ADDR_REG, add);
	outportb(RTC_DATA_REG, value);
	enable_int();
}

/** Write value to I/O address add. Check valid bit
 */
void write_rtcv(Byte add, Byte value)
{
	rtc_valid();
	write_rtc(add, value);
}

/** Read RTC stored time
 *
 * Uses read_rtcv() and bcd2dec()
 */
void rtc_read_time(RTC_TIME * rtc)
{
	rtc->hour = bcd2dec(read_rtcv(HOUR));
	rtc->min = bcd2dec(read_rtcv(MIN));
	rtc->sec= bcd2dec(read_rtcv(SEC));
}

/** Read RTC stored date
 *
 * Uses read_rtcv() and bcd2dec()
 */
void rtc_read_date(RTC_DATE * rtc)
{
	rtc->day = bcd2dec(read_rtcv(MONTH_DAY));
	rtc->month = bcd2dec(read_rtcv(MONTH));
	rtc->year = bcd2dec(read_rtcv(YEAR));
}

/** Read RTC stored alarm
 *
 * Uses read_rtcv() and bcd2dec()
 */
void rtc_read_alarm(RTC_TIME *rtc )
{
	rtc->hour = bcd2dec(read_rtcv(HOUR_ALARM));
	rtc->min = bcd2dec(read_rtcv(MIN_ALARM));
	rtc->sec= bcd2dec(read_rtcv(SEC_ALARM));
}

/** Write alarm to RTC
 *
 * Uses write_rtcv() and dec2bcd()
 */
void rtc_write_alarm(RTC_TIME * alarm)
{
	write_rtcv(HOUR_ALARM , dec2bcd(alarm->hour ));
	write_rtcv( MIN_ALARM, dec2bcd(alarm->min ));
	write_rtcv(SEC_ALARM , dec2bcd( alarm->sec ));
}
